from datetime import datetime
from typing import Optional
from pydantic import BaseModel
from bson import ObjectId

class PyObjectId(ObjectId):
    @classmethod
    def __get_validators__(cls):
        yield cls.validate

    @classmethod
    def validate(cls, v):
        if not ObjectId.is_valid(v):
            raise ValueError("Invalid objectid")
        return ObjectId(v)

    @classmethod
    def __modify_schema__(cls, field_schema):
        field_schema.update(type="string")

class AdvertisementBase(BaseModel):
    title: str
    content: str
    image_url: Optional[str] = None
    target_url: str
    budget: float
    start_time: datetime
    end_time: datetime

class AdvertisementCreate(AdvertisementBase):
    advertiser_id: PyObjectId

class AdvertisementUpdate(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    image_url: Optional[str] = None
    target_url: Optional[str] = None
    budget: Optional[float] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None

class AdvertisementInDBBase(AdvertisementBase):
    id: PyObjectId
    advertiser_id: PyObjectId
    created_at: datetime
    click_count: int = 0
    impression_count: int = 0

    class Config:
        arbitrary_types_allowed = True
        json_encoders = {ObjectId: str}

class Advertisement(AdvertisementInDBBase):
    pass

class AdvertisementInDB(AdvertisementInDBBase):
    pass